from flask import request, g
from flask_jwt_extended import jwt_required, get_jwt_identity
import datetime
from bson import ObjectId

from app.api.v1 import api_bp
from app import mongo
from app.utils.auth import permission_required
from app.schemas.schedule import ScheduleSchema, ScheduleUpdateSchema
from app.utils.common import normalize_data, paginate, jsonify

# 添加一个工具函数，将日期字符串或date对象转换为datetime对象
def convert_to_datetime(date_value):
    """将日期值转换为datetime对象，以便MongoDB可以正确处理"""
    if isinstance(date_value, str):
        # 将字符串转换为datetime对象
        return datetime.datetime.strptime(date_value, '%Y-%m-%d')
    elif isinstance(date_value, datetime.date) and not isinstance(date_value, datetime.datetime):
        # 将date对象转换为datetime对象
        return datetime.datetime.combine(date_value, datetime.time.min)
    return date_value

@api_bp.route('/schedules', methods=['GET'])
@jwt_required()
@permission_required('schedule:read')
def get_schedules():
    """获取排班列表"""
    page = request.args.get('page', 1, type=int)
    limit = request.args.get('limit', 20, type=int)
    sort_by = request.args.get('sortBy', 'date')
    order = request.args.get('order', 'asc')
    
    # 构建查询条件
    query = {}
    
    # 按医生ID筛选
    doctor_id = request.args.get('doctorId')
    if doctor_id:
        query['doctorId'] = doctor_id
    
    # 按科室ID筛选
    department_id = request.args.get('departmentId')
    if department_id:
        query['departmentId'] = department_id
    
    # 按日期范围筛选
    start_date = request.args.get('startDate')
    if start_date:
        try:
            # 使用convert_to_datetime处理开始日期
            start_date = convert_to_datetime(start_date)
            if 'date' not in query:
                query['date'] = {}
            query['date']['$gte'] = start_date
        except ValueError:
            pass
    
    end_date = request.args.get('endDate')
    if end_date:
        try:
            # 使用convert_to_datetime处理结束日期
            end_date = convert_to_datetime(end_date)
            if 'date' not in query:
                query['date'] = {}
            query['date']['$lte'] = end_date
        except ValueError:
            pass
    
    # 按门诊类型筛选
    registration_type = request.args.get('registrationType')
    if registration_type and registration_type != 'all':
        query['registrationType'] = registration_type
    
    # 按状态筛选
    status = request.args.get('status')
    if status and status != 'all':
        query['status'] = status
    
    # 确定排序
    sort_direction = 1 if order.lower() == 'asc' else -1
    
    # 获取数据
    schedules_cursor = mongo.db.schedules.find(query).sort(sort_by, sort_direction)
    
    # 分页
    paginated_data = paginate(schedules_cursor, page, limit)
    
    # 标准化数据并添加医生和科室信息
    schedules = []
    for schedule in paginated_data['items']:
        normalized_schedule = normalize_data(schedule)
        
        # 获取医生信息
        doctor_name = ''
        if 'doctorId' in schedule:
            doctor_id = schedule['doctorId']
            if isinstance(doctor_id, str) and ObjectId.is_valid(doctor_id):
                doctor_id = ObjectId(doctor_id)
            doctor = mongo.db.doctors.find_one({'_id': doctor_id})
            if doctor:
                doctor_name = doctor.get('name', '')
                normalized_schedule['doctorTitle'] = doctor.get('title', '')
        normalized_schedule['doctorName'] = doctor_name
        
        # 获取科室信息
        department_name = ''
        if 'departmentId' in schedule:
            dept_id = schedule['departmentId']
            if isinstance(dept_id, str) and ObjectId.is_valid(dept_id):
                dept_id = ObjectId(dept_id)
            department = mongo.db.departments.find_one({'_id': dept_id})
            if department:
                department_name = department.get('name', '')
        normalized_schedule['departmentName'] = department_name
        
        # 统计已预约数量
        for period, capacity in normalized_schedule.get('remainingCapacity', {}).items():
            if period not in normalized_schedule:
                normalized_schedule[period + 'Reserved'] = 0
            else:
                normalized_schedule[period + 'Reserved'] = normalized_schedule.get(period + 'Capacity', 0) - capacity
        
        schedules.append(normalized_schedule)
    
    return jsonify({
        'success': True,
        'data': {
            'total': paginated_data['total'],
            'page': paginated_data['page'],
            'limit': paginated_data['per_page'],
            'schedules': schedules
        }
    }), 200

@api_bp.route('/schedules', methods=['POST'])
@jwt_required()
@permission_required('schedule:create')
def create_schedule():
    """创建新排班"""
    # 验证请求数据
    schema = ScheduleSchema()
    errors = schema.validate(request.json)
    if errors:
        return jsonify({
            'success': False,
            'message': '请求数据验证失败',
            'errors': errors
        }), 400
    
    data = request.json
    
    # 验证医生是否存在
    doctor_id = data.get('doctorId')
    if not mongo.db.doctors.find_one({'_id': ObjectId(doctor_id)}):
        return jsonify({
            'success': False,
            'message': '医生不存在'
        }), 400
    
    # 验证科室是否存在
    department_id = data.get('departmentId')
    if not mongo.db.departments.find_one({'_id': ObjectId(department_id)}):
        return jsonify({
            'success': False,
            'message': '科室不存在'
        }), 400
    
    # 检查是否存在日期冲突 - 修改这里，使用datetime对象
    date_str = data.get('date')
    if isinstance(date_str, str):
        try:
            # 将字符串日期转换为datetime对象，而不是date对象
            schedule_date = datetime.datetime.strptime(date_str, '%Y-%m-%d')
        except ValueError:
            return jsonify({
                'success': False,
                'message': '日期格式无效'
            }), 400
    else:
        # 如果已经是date对象，转换为datetime
        schedule_date = convert_to_datetime(date_str)
    
    # 更新data中的date为datetime对象
    data['date'] = schedule_date
    
    # 检查该医生在该日期是否已有排班
    existing_schedule = mongo.db.schedules.find_one({
        'doctorId': doctor_id,
        'date': schedule_date
    })
    
    if existing_schedule:
        return jsonify({
            'success': False,
            'message': '该医生在所选日期已有排班'
        }), 400
    
    # 初始化剩余容量
    remaining_capacity = {}
    for time_slot in data.get('timeSlots', []):
        period = time_slot.get('period', '')
        capacity = time_slot.get('capacity', 0)
        if period:
            remaining_capacity[period] = capacity
    
    data['remainingCapacity'] = remaining_capacity
    
    # 设置创建时间和更新时间
    now = datetime.datetime.utcnow()
    data['createdAt'] = now
    data['updatedAt'] = now
    
    # 保存到数据库
    result = mongo.db.schedules.insert_one(data)
    
    # 获取医生和科室信息
    doctor = mongo.db.doctors.find_one({'_id': ObjectId(doctor_id)})
    doctor_name = doctor.get('name', '') if doctor else ''
    
    department = mongo.db.departments.find_one({'_id': ObjectId(department_id)})
    department_name = department.get('name', '') if department else ''
    
    return jsonify({
        'success': True,
        'message': '排班创建成功',
        'data': {
            'id': str(result.inserted_id),
            'doctorName': doctor_name,
            'departmentName': department_name,
            'date': date_str if isinstance(date_str, str) else date_str.isoformat(),
            'createdAt': now.isoformat()
        }
    }), 201

@api_bp.route('/schedules/<id>', methods=['GET'])
@jwt_required()
@permission_required('schedule:read')
def get_schedule(id):
    """获取单个排班详情"""
    # 尝试按ID查找
    if not ObjectId.is_valid(id):
        return jsonify({
            'success': False,
            'message': '无效的排班ID'
        }), 400
    
    schedule = mongo.db.schedules.find_one({'_id': ObjectId(id)})
    
    if not schedule:
        return jsonify({
            'success': False,
            'message': '排班不存在'
        }), 404
    
    # 标准化数据
    normalized_schedule = normalize_data(schedule)
    
    # 获取医生信息
    doctor_info = None
    if 'doctorId' in schedule:
        doctor_id = schedule['doctorId']
        if isinstance(doctor_id, str) and ObjectId.is_valid(doctor_id):
            doctor_id = ObjectId(doctor_id)
        doctor = mongo.db.doctors.find_one({'_id': doctor_id})
        if doctor:
            doctor_info = {
                'id': str(doctor['_id']),
                'staffId': doctor.get('staffId', ''),
                'name': doctor.get('name', ''),
                'title': doctor.get('title', '')
            }
    normalized_schedule['doctorInfo'] = doctor_info
    
    # 获取科室信息
    department_info = None
    if 'departmentId' in schedule:
        dept_id = schedule['departmentId']
        if isinstance(dept_id, str) and ObjectId.is_valid(dept_id):
            dept_id = ObjectId(dept_id)
        department = mongo.db.departments.find_one({'_id': dept_id})
        if department:
            department_info = {
                'id': str(department['_id']),
                'name': department.get('name', ''),
                'location': department.get('location', '')
            }
    normalized_schedule['departmentInfo'] = department_info
    
    # 获取当前预约信息
    appointments = []
    schedule_date = schedule.get('date')
    
    # 确保schedule_date是datetime对象
    if schedule_date:
        schedule_date = convert_to_datetime(schedule_date)
    
    appointments_cursor = mongo.db.appointments.find({
        'scheduleId': str(schedule['_id']),
        'appointmentDate': schedule_date
    }).sort('createdAt', 1)
    
    for appointment in appointments_cursor:
        patient_name = ''
        patient_id = appointment.get('patientId')
        if patient_id and ObjectId.is_valid(patient_id):
            patient = mongo.db.patients.find_one({'_id': ObjectId(patient_id)})
            if patient:
                patient_name = patient.get('name', '')
        
        appointments.append({
            'id': str(appointment['_id']),
            'appointmentId': appointment.get('appointmentId', ''),
            'patientName': patient_name,
            'timeSlot': appointment.get('timeSlot', ''),
            'period': appointment.get('period', ''),
            'status': appointment.get('status', '')
        })
    
    normalized_schedule['appointments'] = appointments
    
    return jsonify({
        'success': True,
        'data': normalized_schedule
    }), 200

@api_bp.route('/schedules/<id>', methods=['PUT'])
@jwt_required()
@permission_required('schedule:update')
def update_schedule(id):
    """更新排班信息"""
    # 验证请求数据
    schema = ScheduleUpdateSchema()
    errors = schema.validate(request.json)
    if errors:
        return jsonify({
            'success': False,
            'message': '请求数据验证失败',
            'errors': errors
        }), 400
    
    # 检查ID是否有效
    if not ObjectId.is_valid(id):
        return jsonify({
            'success': False,
            'message': '无效的排班ID'
        }), 400
    
    data = request.json
    
    # 查找排班
    schedule = mongo.db.schedules.find_one({'_id': ObjectId(id)})
    
    if not schedule:
        return jsonify({
            'success': False,
            'message': '排班不存在'
        }), 404
    
    # 如果已有预约，不允许减少容量
    if 'timeSlots' in data:
        # 获取当前已预约数量
        appointments = mongo.db.appointments.find({
            'scheduleId': str(schedule['_id']),
            'status': {'$ne': '已取消'}
        })
        
        # 按时段统计预约数量
        period_counts = {}
        for appointment in appointments:
            period = appointment.get('period', '')
            if period:
                period_counts[period] = period_counts.get(period, 0) + 1
        
        # 检查新容量是否小于已预约数量
        for time_slot in data['timeSlots']:
            period = time_slot.get('period', '')
            capacity = time_slot.get('capacity', 0)
            if period in period_counts and capacity < period_counts[period]:
                return jsonify({
                    'success': False,
                    'message': f'时段 {period} 的容量不能小于已预约数量 {period_counts[period]}'
                }), 400
        
        # 更新剩余容量
        remaining_capacity = {}
        for time_slot in data['timeSlots']:
            period = time_slot.get('period', '')
            capacity = time_slot.get('capacity', 0)
            if period:
                remaining_capacity[period] = capacity - period_counts.get(period, 0)
        
        data['remainingCapacity'] = remaining_capacity
    
    # 准备更新数据
    update_data = data.copy()
    update_data['updatedAt'] = datetime.datetime.utcnow()
    
    # 更新数据库
    result = mongo.db.schedules.update_one(
        {'_id': ObjectId(id)},
        {'$set': update_data}
    )
    
    if result.modified_count == 0:
        return jsonify({
            'success': False,
            'message': '排班更新失败'
        }), 500
    
    return jsonify({
        'success': True,
        'message': '排班更新成功',
        'data': {
            'id': id,
            'updatedAt': update_data['updatedAt'].isoformat()
        }
    }), 200

@api_bp.route('/schedules/<id>', methods=['DELETE'])
@jwt_required()
@permission_required('schedule:delete')
def delete_schedule(id):
    """删除排班（或标记为停诊）"""
    # 检查ID是否有效
    if not ObjectId.is_valid(id):
        return jsonify({
            'success': False,
            'message': '无效的排班ID'
        }), 400
    
    # 查找排班
    schedule = mongo.db.schedules.find_one({'_id': ObjectId(id)})
    
    if not schedule:
        return jsonify({
            'success': False,
            'message': '排班不存在'
        }), 404
    
    # 检查是否有关联的预约
    has_appointments = mongo.db.appointments.find_one({
        'scheduleId': str(schedule['_id']),
        'status': {'$nin': ['已取消', '未到诊']}
    })
    
    # 如果有有效预约，只将排班标记为停诊
    if has_appointments:
        now = datetime.datetime.utcnow()
        result = mongo.db.schedules.update_one(
            {'_id': ObjectId(id)},
            {
                '$set': {
                    'status': '停诊',
                    'updatedAt': now
                }
            }
        )
        
        if result.modified_count == 0:
            return jsonify({
                'success': False,
                'message': '排班状态更新失败'
            }), 500
        
        # 取消相关预约
        mongo.db.appointments.update_many(
            {
                'scheduleId': str(schedule['_id']),
                'status': {'$nin': ['已取消', '已到诊']}
            },
            {
                '$set': {
                    'status': '已取消',
                    'remarks': '排班停诊自动取消',
                    'updatedAt': now
                }
            }
        )
        
        return jsonify({
            'success': True,
            'message': '排班已标记为停诊，相关预约已取消',
            'data': None
        }), 200
    
    # 如果没有有效预约，可以真正删除
    result = mongo.db.schedules.delete_one({'_id': ObjectId(id)})
    
    if result.deleted_count == 0:
        return jsonify({
            'success': False,
            'message': '排班删除失败'
        }), 500
    
    return jsonify({
        'success': True,
        'message': '排班删除成功',
        'data': None
    }), 200

@api_bp.route('/schedules/batch', methods=['POST'])
@jwt_required()
@permission_required('schedule:create')
def create_batch_schedules():
    """批量创建排班"""
    # 获取请求数据
    data = request.json
    
    if not isinstance(data, dict):
        return jsonify({
            'success': False,
            'message': '无效的请求数据'
        }), 400
    
    # 基本信息验证
    doctor_id = data.get('doctorId')
    if not doctor_id or not ObjectId.is_valid(doctor_id):
        return jsonify({
            'success': False,
            'message': '无效的医生ID'
        }), 400
    
    if not mongo.db.doctors.find_one({'_id': ObjectId(doctor_id)}):
        return jsonify({
            'success': False,
            'message': '医生不存在'
        }), 400
    
    department_id = data.get('departmentId')
    if not department_id or not ObjectId.is_valid(department_id):
        return jsonify({
            'success': False,
            'message': '无效的科室ID'
        }), 400
    
    if not mongo.db.departments.find_one({'_id': ObjectId(department_id)}):
        return jsonify({
            'success': False,
            'message': '科室不存在'
        }), 400
    
    dates = data.get('dates', [])
    if not dates or not isinstance(dates, list):
        return jsonify({
            'success': False,
            'message': '至少需要一个日期'
        }), 400
    
    time_slots = data.get('timeSlots', [])
    if not time_slots or not isinstance(time_slots, list):
        return jsonify({
            'success': False,
            'message': '至少需要一个时间段'
        }), 400
    
    # 准备共用数据
    common_data = {
        'doctorId': doctor_id,
        'departmentId': department_id,
        'timeSlots': time_slots,
        'room': data.get('room', ''),
        'registrationType': data.get('registrationType', '普通门诊'),
        'registrationFee': data.get('registrationFee', 0.0),
        'status': data.get('status', '正常'),
        'remarks': data.get('remarks', '')
    }
    
    # 初始化剩余容量
    remaining_capacity = {}
    for time_slot in time_slots:
        period = time_slot.get('period', '')
        capacity = time_slot.get('capacity', 0)
        if period:
            remaining_capacity[period] = capacity
    
    common_data['remainingCapacity'] = remaining_capacity
    
    # 创建时间
    now = datetime.datetime.utcnow()
    common_data['createdAt'] = now
    common_data['updatedAt'] = now
    
    # 批量插入结果
    result_ids = []
    success_count = 0
    error_dates = []
    
    for date_str in dates:
        try:
            # 使用convert_to_datetime函数处理日期
            schedule_date = convert_to_datetime(date_str)
            
            # 检查该医生在该日期是否已有排班
            existing_schedule = mongo.db.schedules.find_one({
                'doctorId': doctor_id,
                'date': schedule_date
            })
            
            if existing_schedule:
                error_dates.append({
                    'date': date_str,
                    'reason': '该日期已有排班'
                })
                continue
            
            # 创建新排班
            schedule_data = common_data.copy()
            schedule_data['date'] = schedule_date
            
            result = mongo.db.schedules.insert_one(schedule_data)
            result_ids.append(str(result.inserted_id))
            success_count += 1
            
        except ValueError:
            error_dates.append({
                'date': date_str,
                'reason': '日期格式无效'
            })
    
    return jsonify({
        'success': True,
        'message': f'成功创建 {success_count} 条排班记录',
        'data': {
            'successCount': success_count,
            'ids': result_ids,
            'errorDates': error_dates
        }
    }), 200 